
#include <stdio.h>

#include "olisp.h"

#include "utility/olisp_macro_subst.h"

#define UNIT_TESTS_FOLDER "../../unit_tests/"

static void handle_interpreting1(
    reader_context * rdr_ctx,
    printer_context * prn_ctx,
    interpreter_t * interpreter
    )
{
    // read each element from stream and interpret it
    for( ;; )
    {
        obj_t * e = read_elem( rdr_ctx );
        if( e )
        {
            obj_t * interpreted = interpreter_interpret( interpreter, e );
            if( interpreted )
            {
                print_elem( e, prn_ctx );
                fprintf( prn_ctx->stream, " -> " );
                print_elem( interpreted, prn_ctx );
                fprintf( prn_ctx->stream, "\n" );

                RELEASE( interpreted );
            }

            RELEASE( e );
        }
        else
        {
            fprintf( prn_ctx->stream, "END reading\n" );
            break;
        }
    }
}

static void handle_interpreting2(
    reader_context * rdr_ctx,
    printer_context * prn_ctx,
    interpreter_t * interpreter
    )
{
    // macro expansion test
    macro_substitutor_context_t mac_ctx = { 0 };
    list_obj_t * list;

    fprintf( prn_ctx->stream, "\n== A Preprocessor Test ==\n" );

    mac_ctx.interpreter = interpreter;
    mac_ctx.quote_mgr = rdr_ctx->quote_mgr;
    mac_ctx.stream = rdr_ctx->stream;
    mac_ctx.unprocessed_list = create_list( 0 );

    list = macro_read( &mac_ctx );
    if( list )
    {
        size_t n;
        for( n = 0; n < list_length(list); ++ n )
        {
            if( mac_ctx.unprocessed_list )
            {
                print_elem( list_get_elem(mac_ctx.unprocessed_list, n), prn_ctx );
                fprintf( prn_ctx->stream, " -> " );
            }
            print_elem( list_get_elem(list, n), prn_ctx );
            fprintf( prn_ctx->stream, "\n" );
        }

        RELEASE( list );
    }

    dispose_macro_subst_context( &mac_ctx );
}

static void do_interpret(
    FILE *          in_stream,
    const char *    stream_name,
    FILE *          out_stream,
    FILE *          err_stream
    )
{
    reader_context rdr_ctx = { 0 };
    printer_context prn_ctx = { 0 };
    interpreter_context ir_ctx = { 0 };
    interpreter_t * interpreter = 0;

#ifdef LISP_FEAT_QUOTE_SUPPORT
    // provide quote manager for those who needs it
    lisp_quote_mgr_t * quote_mgr = 0;

    quote_mgr = create_quote_mgr();
    if( !quote_mgr )
        goto LEnd;

    ir_ctx.quote_mgr = rdr_ctx.quote_mgr = prn_ctx.quote_mgr = quote_mgr;
#endif

    // fill interpreter context
    ir_ctx.err_stream = err_stream;

    // create interpreter
    interpreter = create_interpreter( &ir_ctx );
    if( !interpreter )
        goto LEnd;

    // register lisp funcs
    if( !register_lf_arith(interpreter) )
        goto LEnd;

    // fill reader context
    rdr_ctx.stream_name = stream_name;
    rdr_ctx.stream = in_stream;
    rdr_ctx.line = 1; // start with first line
    rdr_ctx.err_handler = interpreter;

    // fill printer context
    prn_ctx.stream = out_stream;

    handle_interpreting2( &rdr_ctx, &prn_ctx, interpreter );

LEnd:
    if( interpreter )
        interpreter_dispose( interpreter );

#ifdef LISP_FEAT_QUOTE_SUPPORT
    if( quote_mgr )
        quote_mgr_dispose( quote_mgr );
#endif
}

void test_interpreter()
{
    const char * filename = UNIT_TESTS_FOLDER "test03.lsp";
    FILE * input_file = fopen( filename, "rb" );

    if( input_file )
    {
        do_interpret( input_file, filename, stdout, stderr );

        fclose( input_file );
    }
    else
    {
        printf( "can't open %s\n", filename );
    }
}

void test()
{
    //test_interpreter();
}

int main( int argc, char * argv[] )
{
    printf( "olisp test02\n" );

    test();

    lisp_dump_mem_leaks();

    getchar();
    return 0;
}
